package org.liaohailong.library.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Outline;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewOutlineProvider;

import androidx.annotation.ColorInt;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatImageView;

import org.liaohailong.library.R;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * Author: Victor
 * Date: 2019/5/8 10:08
 * Description: 可方便实现圆形图 or 圆角矩形
 * Android5.0以上使用ViewOutLineProvider实现
 * Android5.0以下使用clipPath实现
 */
public class ShapeImageView extends AppCompatImageView {

    @Retention(RetentionPolicy.SOURCE)
    @IntDef({Type.RECT, Type.CIRCLE, Type.ROUND_RECT})
    public @interface Type {
        int RECT = -1;
        int CIRCLE = 0;
        int ROUND_RECT = 1;
    }

    /**
     * 圆角半径
     */
    private int cornerRadius;
    /**
     * 边界宽度 px单位
     */
    private int borderWidth;
    /**
     * 边界颜色值
     */
    @ColorInt
    private int borderColor;

    @Type
    private int shapeType;
    private Paint borderPaint;
    private Path path;
    private Rect rect;


    public ShapeImageView(Context context) {
        this(context, null);
    }

    public ShapeImageView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ShapeImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        //解析xml配置信息
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ShapeImageView);
        shapeType = array.getInteger(R.styleable.ShapeImageView_shape_type, Type.RECT);
        cornerRadius = array.getDimensionPixelSize(R.styleable.ShapeImageView_cornerRadius, 0);
        int borderWidth = array.getDimensionPixelSize(R.styleable.ShapeImageView_border_width, 0);
        this.borderWidth = Math.max(0, borderWidth);
        this.borderColor = array.getColor(R.styleable.ShapeImageView_border_color, Color.TRANSPARENT);

        array.recycle();

        init();
    }

    private void init() {
        borderPaint = new Paint();
        borderPaint.setAntiAlias(true);
        borderPaint.setStyle(Paint.Style.STROKE);
        borderPaint.setStrokeWidth(borderWidth);
        borderPaint.setColor(borderColor);

        path = new Path();
        rect = new Rect();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        prepareDrawPath();
        prepareOutlineProvider();
    }

    private void prepareDrawPath() {
        path.reset();
        RectF rectF = new RectF();
        int borderOffset = aboveLollipop() ? borderWidth : (int) Math.ceil(borderWidth / 2f);
        int left = getPaddingLeft() + borderOffset;
        int top = getPaddingTop() + borderOffset;
        int right = getMeasuredWidth() - getPaddingRight() - borderOffset;
        int bottom = getMeasuredHeight() - getPaddingBottom() - borderOffset;
        rectF.set(left, top, right, bottom);

        switch (shapeType) {
            case Type.RECT:
                path.addRect(rectF, Path.Direction.CW);
                rect.set((int) rectF.left, (int) rectF.top, (int) rectF.right, (int) rectF.bottom);
                break;
            case Type.CIRCLE:
                float drawWidth = rectF.width();
                float drawHeight = rectF.height();
                float centerX = rectF.centerX();
                float centerY = rectF.centerY();
                float radius = Math.min(drawWidth, drawHeight) / 2f;
                path.addCircle(centerX, centerY, radius, Path.Direction.CW);

                int circleLeft = (int) (centerX - radius);
                int circleTop = (int) (centerY - radius);
                int circleRight = (int) (centerX + radius);
                int circleBottom = (int) (centerY + radius);
                rect.set(circleLeft, circleTop, circleRight, circleBottom);
                break;
            case Type.ROUND_RECT:
                path.addRoundRect(rectF, cornerRadius, cornerRadius, Path.Direction.CW);
                rect.set((int) rectF.left, (int) rectF.top, (int) rectF.right, (int) rectF.bottom);
                break;
            default:
                break;
        }
    }

    private void prepareOutlineProvider() {
        if (aboveLollipop()) {
            setOutlineProvider(new ViewOutlineProvider() {
                @Override
                public void getOutline(View view, Outline outline) {
                    switch (shapeType) {
                        case Type.RECT:
                            outline.setRect(rect);
                            break;
                        case Type.CIRCLE:
                            outline.setOval(rect);
                            break;
                        case Type.ROUND_RECT:
                            outline.setRoundRect(rect, cornerRadius);
                            break;
                        default:
                            break;
                    }
                }
            });
            setClipToOutline(true);
        }
    }

    /**
     * @return true为5.0以上 false表示以下
     */
    private boolean aboveLollipop() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
    }

    public void setShapeType(@Type int shapeType) {
        if (this.shapeType == shapeType) {
            return;
        }
        this.shapeType = shapeType;
        prepareDrawPath();
        prepareOutlineProvider();
        invalidate();
    }

    @Type
    public int getShapeType() {
        return shapeType;
    }

    public void setRadius(int radius) {
        cornerRadius = radius;
        prepareDrawPath();
        prepareOutlineProvider();
        invalidate();
    }

    public void setBorder(int borderWidth, @ColorInt int borderColor) {
        this.borderWidth = borderWidth;
        this.borderColor = borderColor;
        borderPaint.setColor(borderColor);
        borderPaint.setStrokeWidth(borderWidth);
        prepareDrawPath();
        prepareOutlineProvider();
        invalidate();
    }

    @Override
    public void draw(Canvas canvas) {
        // 裁剪背景图形
        if (aboveLollipop()) {
            super.draw(canvas);
        } else {
            int saveCount = canvas.save();
            canvas.clipPath(path);
            super.draw(canvas);
            canvas.restoreToCount(saveCount);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        // 裁剪图片形状
        if (aboveLollipop()) {
            super.onDraw(canvas);
        } else {
            int saveCount = canvas.save();
            canvas.clipPath(path);
            super.onDraw(canvas);
            canvas.restoreToCount(saveCount);
        }

        // 绘制边线
        drawBorder(canvas, path);
    }

    private void drawBorder(Canvas canvas, Path path) {
        canvas.drawPath(path, borderPaint);
    }
}
